package ynu.edu.stats.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import ynu.edu.common.constant.RedisConstants;
import ynu.edu.common.domain.stats.CategoryStat;
import ynu.edu.common.domain.stats.StatsData;
import ynu.edu.common.domain.stats.UserGrowthData;
import ynu.edu.common.utils.RedisCache;
import ynu.edu.stats.properties.RabbitmqStatsProperties;
import ynu.edu.stats.service.StatsService;


import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
@Slf4j
public class StatsServiceImpl implements StatsService {

    private final RedisCache redisCache;

    private final RabbitTemplate rabbitTemplate;

    private final RedissonClient redissonClient;

    private final RabbitmqStatsProperties rabbitmqStatsProperties;

    private final ObjectMapper objectMapper;


    @Override
    public StatsData<List<CategoryStat>> getItemStats() {
        // 从 Redis 中直接取出封装好的 StatsData<List<CategoryStat>> 对象
        StatsData<List<CategoryStat>> statsData = redisCache.getCacheObject(
                RedisConstants.ITEM_STATS_KEY,
                new TypeReference<StatsData<List<CategoryStat>>>() {}
        );

        if (statsData != null && "SUCCESS".equals(statsData.getStatus())) {
            return statsData;
        }

        Object result = handleCacheMiss(
                RedisConstants.ITEM_STATS_KEY,
                RedisConstants.ITEM_STATS_LOCK,
                RedisConstants.ITEM_STATS_UPDATING_KEY,
                rabbitmqStatsProperties.getItemRoutingKey()
        );

        // 如果正在更新中
        if (result instanceof Map map && map.containsKey("msg")) {
            return StatsData.updating();
        }

        // 如果返回了完整数据，则构建 StatsData 返回
        if (result instanceof Map<?, ?> resultMap &&
                resultMap.containsKey("detail") &&
                resultMap.containsKey("total")) {

            List<CategoryStat> list = objectMapper.convertValue(resultMap.get("detail"), new TypeReference<List<CategoryStat>>() {});
            Long total = objectMapper.convertValue(resultMap.get("total"), Long.class);
            return StatsData.success(list, total);
        }

        return StatsData.error("获取商品统计数据失败");
    }

    /**
     * 获取最近7天用户增长统计数据
     */
    @Override
    public StatsData<UserGrowthData> getUserGrowthStats() {
        // 从 Redis 中直接取出封装好的 StatsData<UserGrowthData> 对象
        StatsData<UserGrowthData> statsData = redisCache.getCacheObject(
                RedisConstants.USER_GROWTH_STATS_KEY,
                new TypeReference<StatsData<UserGrowthData>>() {}
        );


        if (statsData != null && "SUCCESS".equals(statsData.getStatus())) {
            return statsData;
        }

        Object result = handleCacheMiss(
                RedisConstants.USER_GROWTH_STATS_KEY,
                RedisConstants.USER_GROWTH_STATS_LOCK,
                RedisConstants.USER_GROWTH_STATS_UPDATING_KEY,
                rabbitmqStatsProperties.getUserGrowthRoutingKey()
        );

        if (result instanceof UserGrowthData data) {
            long total = data.getCounts().stream().mapToInt(Integer::intValue).sum();
            return StatsData.success(data, total);
        } else if (result instanceof Map && ((Map<?, ?>) result).containsKey("msg")) {
            return StatsData.updating();
        } else {
            return StatsData.error("获取用户增长统计失败");
        }
    }

    /**
     * 缓存未命中后的处理逻辑
     */
    private Object handleCacheMiss(String statsKey, String lockKey, String updatingKey, String routingKey) {
        if (redisCache.getCacheObject(updatingKey, String.class) != null) {
            return Map.of("msg", "数据更新中，请稍后重试");
        }

        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(2, 30, TimeUnit.SECONDS)) {
                try {
                    Object recheckData = redisCache.getCacheObject(statsKey, Object.class);
                    if (recheckData != null) {
                        return recheckData;
                    }

                    // 设置更新标记
                    redisCache.setCacheObject(updatingKey, "true", 30, TimeUnit.SECONDS);

                    // 发送 MQ 消息，异步更新
                    rabbitTemplate.convertAndSend(
                            rabbitmqStatsProperties.getExchange().getName(),
                            routingKey,
                            "update_stats"
                    );
                    log.info("[StatsServiceImpl] 触发异步统计更新: {}", routingKey);

                    return Map.of("msg", "数据即将更新，请稍后重试");
                } finally {
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("[StatsServiceImpl] 锁获取中断: {}", lockKey, e);
        } catch (Exception e) {
            log.error("[StatsServiceImpl] 获取缓存失败", e);
        }

        return Map.of("msg", "系统繁忙，请稍后重试");
    }

}